#pragma once

#include "socket.hpp"
#include <sstream>
#include <fstream>
#include <vector>
#include <string>

const string http_sep = "\r\n";
const string wwwroot = "/home/cr/git/network/HttpProtocol/www.root";  // 这就是url下的根目录/
const string homepage = "index.html"; // 访问根目录下的默认文件

class HttpRequest
{
    bool Get_line(string &request, string &ret) // 实现读取每一行数据的功能
    {
        int pos = request.find(http_sep);
        if (pos == string::npos)
            return false;

        ret = request.substr(0, pos);
        request.erase(0, pos + http_sep.size());
        return true;
    }

public:
    HttpRequest()
        : _req_blank(http_sep), _targetpath(wwwroot)
    {
    }

    void Parse_reqline() // 分析请求行,并根据url确定路径_targetpath
    {
        //_method _url _http_version
        stringstream ss(_req_line);
        ss >> _method >> _url >> _http_version; // 以空格作为分隔符一次放到三个string流中

        // 路径解析
        if (_url == "/")
        {
            _targetpath += "/" + homepage;
        }
        else // 粗略处理
        {
            _targetpath += _url;
        }
    }

private:
    void Parse_suffix()
    {
        //_targetpath: www.root/image/1.jpg
        int pos = _targetpath.rfind('.');
        if (pos == string::npos)
            _suffix = "未知类型";
        else
            _suffix = _targetpath.substr(pos);
    }

public:
    void parse() // 报文分析
    {
        // 1.分析请求行,同时提取url路径
        Parse_reqline();

        // 2.解析url下的指定文件类型即后缀
        Parse_suffix();
    }

    string Get_filecontent_func(string path) // 读取指定路径下的数据
    {
        ifstream in(path, ios::binary); // 按照二进制方式来读取
        if (!in.is_open())
            return "";

        string ret;

        // a.读取一般非二进制数据的方法
        // string line;
        //  while (getline(in, line))
        //  {
        //      ret += line;
        //  }

        // getline不能拿来读取二进制文件
        // 1.换行符问题 2.性能问题

        // b.读取二进制数据
        in.seekg(0, in.end);        // 文件流偏移到结尾数
        int file_size = in.tellg(); // 读取文件大小
        in.seekg(0, in.beg);        // 回到文件开头指向

        ret.resize(file_size);
        in.read((char *)ret.c_str(), file_size);

        in.close();
        return ret;
    }
    string Get_filecontent()
    {
        return Get_filecontent_func(_targetpath);
    }
    string Get_404()
    {
        return Get_filecontent_func("www.root/404.html");
    }

    void Deserialize(string request) // 反序列化
    {
        Get_line(request, _req_line);
        string line;
        while (1)
        {
            bool ok = Get_line(request, line);
            if (ok && line.empty()) // 读到空行,即报头解析完毕
            {
                _req_content = request; // 空行后面就是实际内容
                break;
            }
            else if (ok && !line.empty()) // 读取报头数据
            {
                _req_header.push_back(line);
            }
            else
                break;
        }
    }

    string Url()
    {
        return _url;
    }
    string Path()
    {
        return _targetpath;
    }
    string Suffix()
    {
        return _suffix;
    }

    void my_debug(pthread_t id)
    {
        std::string filePath = "LogFile/" + to_string(id) + ".txt";
        std::ofstream outFile(filePath);
        if (outFile.is_open())
        {
            outFile << "------------------------------------" << std::endl;
            outFile << "_req_line-> " << _req_line << std::endl;
            for (auto s : _req_header)
            {
                outFile << "_req_header-> " << s << endl;
            }
            outFile << "_req_blank-> " << _req_blank << endl;
            outFile << "_req_content-> " << _req_content << endl;
            outFile << "------------------------------------" << endl;

            // 关闭文件
            outFile.close();
            std::cout << "数据已成功写入 " << filePath << std::endl;
        }
        else
        {
            std::cerr << "无法打开文件 " << filePath << std::endl;
        }
    }

private:
    // 报文字段
    string _req_line;           // 请求行（请求方法，url，http版本）
    vector<string> _req_header; // 请求报头
    string _req_blank;          // 空行(区分请求报头和有效载荷的，载荷长度就在报头中解析得到)
    string _req_content;        // 有效载荷

private: // 解析请求行字段
    //_method _url _http_version
    string _method;
    string _url;
    string _http_version;
    string _targetpath; // url指定路径

    string _suffix; // 通过url确定访问的文件后缀
};

const string blank_sep = " ";
const string line_sep = "\r\n";

class HttpRsponse
{
public:
    HttpRsponse()
        : _http_version("Http/1.0"), _status_code(200), _statuscode_desc("OK"), _rsp_blank(line_sep)
    {
    }

    void Set_statuscode(int code)
    {
        _status_code = code;
    }

    void Set_statuscode_desc(string s)
    {
        _statuscode_desc = s;
    }

    string Serialize(const string &httpheader, const string &content)
    {
        // 1.添加状态行数据、报头数据、换行、正文
        _status_line = _http_version + blank_sep + to_string(_status_code) +
                       blank_sep + _statuscode_desc + line_sep;
        string rsp_content = _status_line + httpheader + line_sep + content;
        return rsp_content;
    }

    ~HttpRsponse() {}

private:
    string _status_line;        // 状态行（响应行）
    vector<string> _rsp_header; // 响应报头
    string _rsp_blank;          // 空行
    string _rsp_content;        // 正文

private:
    //_http_version _status_code _statuscode_desc
    string _http_version;    // 版本
    int _status_code;        // 状态码
    string _statuscode_desc; // 状态码描述
};